#!/usr/bin/env python
# coding=utf-8
# @FileName :common.py.py
# @Time     :2022/2/9 19:13
# @Author   :ZXC
# @Desc     :
import json
import re
import allure
from string import Template
from typing import Any
from loguru import logger
from tools.hooks import *


def exec_func(func: str) -> str:
    """
    执行函数(exec可以执行Python代码)
    :param func: 字符的形式调用函数
    :return: 返回的将是个str类型的结果
    """
    # 得到一个局部的变量字典，来修正exec函数中的变量，在其他函数内部使用不到的问题
    loc = locals()
    # {func}会自动执行func对应的方法
    exec(f"result = {func}")
    return str(loc['result'])


def extractor(obj: dict, expr: str = '.') -> Any:
    """
    根据jsonpath表达式提取字典中的value，
    表达式, . 提取字典所有内容， $.case 提取一级字典case， $.case.data 提取case字典下的data
    :param obj: json/dict类型数据
    :param expr: 表达式, . 提取字典所有内容， $.case 提取一级字典case， $.case.data 提取case字典下的data
                $.0.1 提取字典中的第一个列表中的第二个的值
    :return:
    """
    try:
        result = jsonpath(obj, expr)[0]
    except TypeError as e:
        logger.info(f'提取表达式：{expr} - 不存在,返回匹配表达式{e}')
        result = expr
    except Exception as e:
        logger.error(f'提取表达式：{expr} - 提取失败,返回匹配表达式{e}')
        result = expr
    logger.debug(f'提取完成，提取结果为===>{result}')
    return result


def rep_expr(content: str, data: dict) -> str:
    """
    从请求参数的字符串中，使用正则的方法找出合适的字符串内容并进行替换(在接口请求时使用)
    :param content: 原始的字符串内容
    :param data: 提取的参数变量池
    return content： 替换表达式后的字符串
    """
    # 替换content中在data中匹配的数据，匹配格式为${变量名}
    content = Template(content).safe_substitute(data)
    # 从参数变量池子替换不掉的，再在方法里查找替换
    # 提取以${}$包裹的字符串，例如${test_replace()}$
    for func in re.findall('\\${(.*?)}\\$', content):
        try:
            # 提取以${}$包裹的字符串方法，例如${test_replace()}$，用方法的执行结果替换
            content = content.replace('${%s}$' % func, exec_func(func))
        except Exception as e:
            logger.error(f'请求方法匹配替换失败，请求参数{content}，参数变量池{data}，====>失败原因{e}')
    # 处理MYSQL
    for mysql_str in re.findall('\\$M{(.*?)}M\\$', content):
        try:
            # 提取以$M{}M$包裹的字符串方法，例如$M{mysql语句}M$，用方法的执行结果替换
            content = content.replace('$M{%s}M$' % mysql_str, exec_mysql(mysql_str))
        except Exception as e:
            logger.error(f'MYSQL匹配替换失败，请求参数{content}，参数变量池{data}，====>失败原因{e}')
    # 处理TIDB
    for tidb_str in re.findall('\\$T{(.*?)}T\\$', content):
        try:
            # 提取以$T{}T$包裹的字符串方法，例如$T{tidb语句}T$，用方法的执行结果替换
            content = content.replace('$T{%s}T$' % tidb_str, exec_tidb(tidb_str))
        except Exception as e:
            logger.error(f'TIDB匹配替换失败，请求参数{content}，参数变量池{data}，====>失败原因{e}')
    return content


def convert_json(dict_str: str) -> dict:
    """
    反序列化
    :param dict_str: 长得像字典的字符串
    return json格式的内容
    """
    try:
        logger.debug(f'正在执行字符串序列化{dict_str}')
        # 将字符串中Python格式的指定字符替换为json格式的
        if 'None' in dict_str:
            dict_str = dict_str.replace('None', 'null')
        elif 'True' in dict_str:
            dict_str = dict_str.replace('True', 'true')
        elif 'False' in dict_str:
            dict_str = dict_str.replace('False', 'false')
        # 执行json转dict
        dict_str = json.loads(dict_str)
    except Exception as e:
        if 'null' in dict_str:
            dict_str = dict_str.replace('null', 'None')
        elif 'true' in dict_str:
            dict_str = dict_str.replace('true', 'True')
        elif 'false' in dict_str:
            dict_str = dict_str.replace('false', 'False')
        dict_str = eval(dict_str)
        logger.error(f"json转换成字典出错{e}")
    return dict_str


def allure_title(title: str) -> None:
    """
    allure中显示的用例标题
    :param title: 标题内容
    :return:
    """
    allure.dynamic.title(title)


def allure_step(step: str, var) -> None:
    """
    操作步骤及附件
    :param step: 步骤及附件名称
    :param var: 附件内容
    """
    with allure.step(step):
        allure.attach(
            json.dumps(
                var,
                ensure_ascii=False,
                indent=4),
            step,
            allure.attachment_type.JSON)


def allure_step_no(step: str):
    """
    无附件的操作步骤
    :param step: 步骤名称
    :return:
    """
    with allure.step(step):
        pass


if __name__ == '__main__':
    # print(ReadFile.get_config_dict())
    # print(ReadFile.read_config('$.server'))
    # cases = ReadFile.read_testcase()
    # extra_pool = {
    #     'get_current_highest': get_current_highest
    # }
    # for i in cases:
    #     print(i)
    #     print(rep_expr(i.get('请求数据'), extra_pool))
    pass
